/*
 *Copyright 2021-2023 NERCIS
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 */

/*
 *Copyright 2021-2023 NERCIS
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 */

package cn.ac.nercis.pes.service.project.imported;

import cn.ac.nercis.pes.model.dto.common.Result;
import cn.ac.nercis.pes.model.dto.project.ImportConflictDTO;
import cn.ac.nercis.pes.model.standard.report.EvaluationReportSDTO;
import cn.ac.nercis.pes.repository.dal.report.EvaluationReportRepository;
import cn.ac.nercis.pes.repository.model.report.EvaluationReportDO;
import cn.ac.nercis.pes.service.utils.CheckFieldUtils;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 报告生成信息导入服务
 *
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
@Service
public class EvaluationReportImportService {
    private final EvaluationReportRepository evaluationReportRepository;

    public EvaluationReportImportService(EvaluationReportRepository evaluationReportRepository) {
        this.evaluationReportRepository = evaluationReportRepository;
    }

    public Result<List<ImportConflictDTO>> checkEvaluationReport(@NonNull String systemId, List<EvaluationReportSDTO> evaluationReports) {
        List<EvaluationReportDO> sourceData = this.evaluationReportRepository.findAllBySystemId(systemId);
        if (CollectionUtils.isEmpty(sourceData)) {
            return Result.success();
        }
        List<ImportConflictDTO> conflictData = evaluationReports.stream()
                .flatMap(ec -> this.checkEvaluationReport(ec, sourceData).stream())
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        return Result.success(conflictData);
    }

    public Result<String> importEvaluationReport(@NonNull String systemId, List<EvaluationReportSDTO> evaluationReports, Boolean cover) {
        List<EvaluationReportDO> sourceData = this.evaluationReportRepository.findAllBySystemId(systemId);
        Result<String> result = Result.success();
        for (EvaluationReportSDTO item : evaluationReports) {
            result = this.importEvaluationReport(systemId, item, sourceData, cover);
            if (!result.isSuccess()) {
                break;
            }
        }
        return result;
    }

    private List<ImportConflictDTO> checkEvaluationReport(@NonNull EvaluationReportSDTO importData, List<EvaluationReportDO> sourceData) {
        EvaluationReportDO entity = sourceData.stream()
                .filter(st -> st.getReportType() == importData.getReportType())
                .findFirst().orElse(null);
        if (Objects.isNull(entity)) {
            return Collections.emptyList();
        }
        return CheckFieldUtils.checkField(entity, importData);
    }

    private Result<String> importEvaluationReport(String systemId, @NonNull EvaluationReportSDTO importData, List<EvaluationReportDO> sourceData, Boolean cover) {
        EvaluationReportDO entity = sourceData.stream()
                .filter(st -> st.getReportType() == importData.getReportType())
                .findFirst().orElse(null);
        if (Objects.isNull(entity)) {
            return createEvaluationReport(systemId, importData,sourceData);
        } else {
            return modifyEvaluationReport(entity, importData, cover);
        }
    }

    private Result<String> createEvaluationReport(String systemId, EvaluationReportSDTO importData, List<EvaluationReportDO> sourceData) {
        EvaluationReportDO entity = EvaluationReportDO.builder()
                .systemId(systemId)
                .code(importData.getCode())
                .distributionRange(importData.getDistributionRange())
                .evaluationCount(importData.getEvaluationCount())
                .reportType(importData.getReportType())
                .reportTime(importData.getReportTime())
                .build();
        entity.setCreateTime(LocalDateTime.now());
        return Optional.of(entity)
                .map(this.evaluationReportRepository::save)
                .map(er->{
                    sourceData.add(er);
                    return Result.success(er.getId());
                })
                .orElse(Result.failed("导入报告生成信息，创建失败"));
    }

    private Result<String> modifyEvaluationReport(EvaluationReportDO sourceData, EvaluationReportSDTO importData, Boolean cover) {
        sourceData.setCode(CheckFieldUtils.applyContent(sourceData.getCode(), importData.getCode(), cover));
        sourceData.setDistributionRange(CheckFieldUtils.applyContent(sourceData.getDistributionRange(), importData.getDistributionRange(), cover));
        sourceData.setEvaluationCount(CheckFieldUtils.applyContent(sourceData.getEvaluationCount(), importData.getEvaluationCount(), cover));
        sourceData.setReportTime(CheckFieldUtils.applyContent(sourceData.getReportTime(), importData.getReportTime(), cover));
        sourceData.setModifyTime(LocalDateTime.now());
        return Optional.of(sourceData)
                .map(this.evaluationReportRepository::save)
                .map(EvaluationReportDO::getId)
                .map(Result::success)
                .orElse(Result.failed("导入报告生成信息，修改失败"));
    }
}
